const fs = require("fs");
const path = require("path");
const os = require("os");
const StreamZip = require("node-stream-zip");
const Upload = require("../../models/upload");
const UEInstance = require("../../models/ueInstance");
const socketClientManager = require("../socketClient");

class UEProjectManager {
  constructor() {
    this.projectsDir = path.join(__dirname, "../../../projects");
    this.keyPath = path.join(__dirname, "../../../WebTrans.key.bak");
    this.localFileDir = path.join(__dirname, "../../../handleDeploy");
    this.uploadsDir = path.join(__dirname, "../../../uploads");
    this._ensureProjectsDirectory();
  }

  _ensureProjectsDirectory() {
    if (!fs.existsSync(this.projectsDir)) {
      fs.mkdirSync(this.projectsDir, { recursive: true });
      console.log(`Created projects directory: ${this.projectsDir}`);
    }
  }

  // 分页查询上传记录
  async getUploads(page = 1, pageSize = 10, filters = {}) {
    try {
      const query = {};

      // 添加过滤条件
      if (filters.status) {
        query.status = filters.status;
      }
      if (filters.extractStatus) {
        query.extractStatus = filters.extractStatus;
      }
      if (filters.originalName) {
        query.originalName = { $regex: filters.originalName, $options: "i" };
      }

      const total = await Upload.countDocuments(query);
      const findQuery = Upload.find(query).sort({ createdAt: -1 });

      // 当pageSize为-1时返回所有数据，否则进行分页
      if (pageSize !== -1) {
        findQuery.skip((page - 1) * pageSize).limit(pageSize);
      }

      const uploads = await findQuery;

      return {
        data: uploads,
        pagination: {
          total,
          page,
          pageSize,
          totalPages: Math.ceil(total / pageSize),
        },
      };
    } catch (error) {
      console.error("Error fetching uploads:", error);
      throw new Error("Failed to fetch uploads");
    }
  }

  // 批量解压文件
  async extractFiles(fileId) {
    try {
      const upload = await Upload.findOne({ _id: fileId });

      if (!upload) {
        throw new Error("未找到指定的上传记录");
      }

      // 检查文件是否存在且状态正确
      if (upload.status !== "completed") {
        console.warn(
          `Upload ${upload._id} is not completed, skipping extraction`
        );
        return { success: false, message: "文件尚未完成上传，无法解压" };
      }

      // 生成解压目标路径
      const extractDir = path.join(this.projectsDir, upload.fileHash);
      const zipFilePath = path.join(
        __dirname,
        "../../../uploads",
        upload.fileHash + path.extname(upload.originalName)
      );

      // 检查zip文件是否存在
      if (!fs.existsSync(zipFilePath)) {
        throw new Error("找不到上传的zip文件");
      }

      // 更新解压状态
      upload.extractStatus = "extracting";
      upload.extractStartTime = new Date();
      // upload.extractPath = `/projects/${upload.fileHash}`;
      await upload.save();

      // 发送开始解压通知
      socketClientManager.sendToModule("ueProject", {
        type: "extract_started",
        payload: {
          uploadId: upload._id,
          fileHash: upload.fileHash,
        },
      });

      // 异步处理解压过程
      this._processExtraction(zipFilePath, extractDir, upload).catch(
        async (error) => {
          console.error(`Extraction failed for ${upload._id}:`, error);
          try {
            upload.extractStatus = "failed";
            await upload.save();
            socketClientManager.sendToModule("ueProject", {
              type: "extract_error",
              payload: {
                uploadId: upload._id,
                fileHash: upload.fileHash,
                error: error.message,
              },
            });
          } catch (dbError) {
            console.error(
              `Failed to update upload status to 'failed' for ${upload._id} after extraction error:`,
              dbError
            );
          }
        }
      );

      return {
        success: true,
        message: "解压任务已启动，请通过WebSocket监听解压进度",
        uploadId: upload._id,
        fileHash: upload.fileHash,
      };
    } catch (error) {
      console.error("Error extracting files:", error);
      throw new Error("Failed to extract files");
    }
  }

  // 批量删除解压文件
  async deleteExtractedFiles(fileId) {
    try {
      const upload = await Upload.findOne({ _id: fileId });

      if (!upload) {
        throw new Error("未找到指定的上传记录");
      }

      if (upload.extractStatus !== "completed") {
        console.warn(
          `Upload ${upload._id} is not extracted, skipping deletion`
        );
        return { success: false, message: "文件尚未解压，无法删除" };
      }
      // 查询关联的ue进程
      const ueInstance = await UEInstance.findOne({
        projectId: fileId,
      });
      if (ueInstance) {
        return {
          success: false,
          message: "请先停止相关联的UE进程",
          fileName: upload.originalName,
        };
      }

      //  生成解压目标路径
      const extractPath = path.join(this.projectsDir, upload.fileHash);

      // 检查目录是否存在
      if (!fs.existsSync(extractPath)) {
        throw new Error("解压文件目录不存在");
      }

      // 更新删除状态为删除中
      upload.extractStatus = "deleting";
      await upload.save();

      // 发送开始删除通知
      socketClientManager.sendToModule("ueProject", {
        type: "delete_started",
        payload: {
          uploadId: upload._id,
          fileHash: upload.fileHash,
        },
      });

      // 异步处理删除过程
      this._processDelete(extractPath, upload).catch(async (error) => {
        console.error(`Deletion failed for ${upload._id}:`, error);
        try {
          upload.extractStatus = "failed";
          await upload.save();
          socketClientManager.sendToModule("ueProject", {
            type: "delete_error",
            payload: {
              uploadId: upload._id,
              fileHash: upload.fileHash,
              error: error.message,
            },
          });
        } catch (dbError) {
          console.error(
            `Failed to update upload status to 'failed' for ${upload._id} after deletion error:`,
            dbError
          );
        }
      });

      return {
        success: true,
        message: "删除任务已启动，请通过WebSocket监听删除进度",
        uploadId: upload._id,
        fileHash: upload.fileHash,
      };
    } catch (error) {
      console.error("Error deleting extracted files:", error);
      throw new Error("Failed to delete extracted files");
    }
  }
  async deleteZipAndExtractedFiles(fileId) {
    try {
      const upload = await Upload.findOne({ _id: fileId });

      if (!upload) {
        throw new Error("未找到指定的上传记录");
      }
      // 查询关联的ue进程
      const ueInstance = await UEInstance.findOne({
        projectId: fileId,
      });
      if (ueInstance) {
        return {
          success: false,
          message: "请先停止相关联的UE进程",
          fileName: upload.originalName,
        };
      }
      // 获取文件路径
      const extractPath = path.join(this.projectsDir, upload.fileHash);
      const zipFilePath = path.join(
        __dirname,
        "../../../uploads",
        upload.fileHash + path.extname(upload.originalName)
      );

      // 更新状态为删除中
      upload.status = "deleting";
      await upload.save();

      // 发送开始删除通知
      socketClientManager.sendToModule("ueProject", {
        type: "delete_all_started",
        payload: {
          uploadId: upload._id,
          fileHash: upload.fileHash,
        },
      });

      // 异步处理删除过程
      this._processDeleteAll(extractPath, zipFilePath, upload, fileId).catch(
        async (error) => {
          console.error(`Complete deletion failed for ${upload._id}:`, error);
          try {
            upload.status = "failed";
            await upload.save();
            socketClientManager.sendToModule("ueProject", {
              type: "delete_all_error",
              payload: {
                uploadId: upload._id,
                fileHash: upload.fileHash,
                error: error.message,
              },
            });
          } catch (dbError) {
            console.error(
              `Failed to update upload status to 'failed' for ${upload._id} after deletion error:`,
              dbError
            );
          }
        }
      );

      return {
        success: true,
        message: "删除任务已启动，请通过WebSocket监听删除进度",
        uploadId: upload._id,
        fileHash: upload.fileHash,
      };
    } catch (error) {
      console.error("Error in deleteZipAndExtractedFiles:", error);
      throw new Error("Failed to delete files and records");
    }
  }
  // 处理删除过程
  async _processDelete(extractPath, upload) {
    try {
      // 使用fs.rm递归删除目录
      await fs.promises.rm(extractPath, { recursive: true, force: true });

      // 更新删除完成状态
      upload.extractStatus = "deleted";
      await upload.save();

      // 发送删除完成通知
      socketClientManager.sendToModule("ueProject", {
        type: "delete_completed",
        payload: {
          uploadId: upload._id,
          fileHash: upload.fileHash,
          extractPath: upload.extractPath,
          fileName: upload.originalName,
        },
      });
    } catch (error) {
      throw error;
    }
  }

  // 处理完整删除过程
  async _processDeleteAll(extractPath, zipFilePath, upload, fileId) {
    try {
      // 如果解压文件存在，先删除解压文件
      if (fs.existsSync(extractPath)) {
        await fs.promises.rm(extractPath, { recursive: true, force: true });
        // 更新删除完成状态
        upload.extractStatus = "deleted";
        await upload.save();
      }

      // 删除zip文件
      if (fs.existsSync(zipFilePath)) {
        await fs.promises.unlink(zipFilePath);
      }

      // 删除数据库记录
      await Upload.deleteOne({ _id: fileId });

      // 发送删除完成通知
      socketClientManager.sendToModule("ueProject", {
        type: "delete_all_completed",
        payload: {
          uploadId: upload._id,
          fileHash: upload.fileHash,
          fileName: upload.originalName,
        },
      });
    } catch (error) {
      throw error;
    }
  }

  // 处理解压过程
  async _processExtraction(zipFilePath, extractDir, upload) {
    const zip = new StreamZip.async({ file: zipFilePath });
    try {
      const entriesCount = await zip.entriesCount;
      let processedCount = 0;

      // 确保解压目录存在
      if (!fs.existsSync(extractDir)) {
        fs.mkdirSync(extractDir, { recursive: true });
      }

      // 获取所有文件条目
      const entries = await zip.entries();

      // 遍历解压每个文件
      for (const entry of Object.values(entries)) {
        const targetPath = path.join(extractDir, entry.name);
        const targetDir = path.dirname(targetPath);

        // 确保目标目录存在
        if (!fs.existsSync(targetDir)) {
          fs.mkdirSync(targetDir, { recursive: true });
        }

        // 解压文件
        if (!entry.isDirectory) {
          await zip.extract(entry.name, targetPath);
        }

        // 更新进度
        processedCount++;
        const progress = Math.floor((processedCount / entriesCount) * 100);

        // 发送进度通知
        socketClientManager.sendToModule("ueProject", {
          type: "extract_progress",
          payload: {
            uploadId: upload._id,
            fileHash: upload.fileHash,
            progress,
            currentFile: entry.name,
          },
        });
      }

      // 关闭zip文件
      await zip.close();
      // 处理webtranskey文件
      const { extractPath, executableName } = await this._handleWebTransKey(
        this.keyPath,
        extractDir
      );
      console.log("extractPath:", extractPath);
      console.log("executableName:", executableName);
      upload.extractPath = extractPath;
      upload.executableName = executableName;
      // 更新解压完成状态
      upload.extractStatus = "completed";
      upload.extractEndTime = new Date();
      await upload.save();

      // 发送解压完成通知
      socketClientManager.sendToModule("ueProject", {
        type: "extract_completed",
        payload: {
          uploadId: upload._id,
          fileHash: upload.fileHash,
          fileName: upload.originalName,
          extractPath: upload.extractPath,
        },
      });
    } catch (error) {
      await zip.close();
      throw error;
    }
  }
  async _handleWebTransKey(keyPath, destDirPath) {
    try {
      // 查找可执行文件路径
      const exeFilePath = await this._findExecutableFile(destDirPath);

      if (!exeFilePath) {
        console.log("未找到可执行文件，跳过key文件装配");
        return;
      }

      console.log(`找到可执行文件: ${exeFilePath}`);

      // 获取可执行文件信息
      const exeFileName = path.basename(exeFilePath);
      const exeNameWithoutExt = path.parse(exeFileName).name;
      const extractPath = path.dirname(exeFilePath);
      // 确定目标文件夹路径（与可执行文件同级）
      const targetFolderPath = path.join(extractPath, exeNameWithoutExt);
      // console.log("目标文件夹路径:", targetFolderPath);
      // console.log("部署目录:", path.dirname(exeFilePath));
      // console.log("可执行文件名:", exeFileName);
      // console.log("可执行文件名（不含扩展名）:", exeNameWithoutExt);
      // 创建目标文件夹（如果不存在）
      await fs.mkdirSync(targetFolderPath, { recursive: true });

      // 构建目标文件路径
      const keyFileName = path.basename(keyPath, ".bak");
      const destFilePath = path.join(targetFolderPath, keyFileName);

      // 检查目标文件是否存在
      try {
        await fs.access(destFilePath);
        console.log("目标文件已存在，跳过复制");
      } catch {
        // 复制并重命名key文件
        await fs.promises.copyFile(keyPath, destFilePath);
        console.log("key文件装配成功！");
      }
      return {
        extractPath: extractPath,
        executableName: exeFileName,
      };
    } catch (err) {
      console.error("key文件装配时发生错误:", err);
      throw err;
    }
  }

  async _findExecutableFile(startPath) {
    const platform = os.platform();
    const isWindows = platform === "win32";
    const executableExt = isWindows ? ".exe" : ".sh";

    // 首先尝试在起始目录直接查找可执行文件
    const directMatch = await this._searchInDirectory(startPath, executableExt);
    if (directMatch) return directMatch;

    // 如果没有找到，查找第一个子目录并递归搜索
    try {
      const files = await fs.promises.readdir(startPath, {
        withFileTypes: true,
      });
      const dirs = files.filter((file) => file.isDirectory());

      if (dirs.length > 0) {
        // 按名称排序以确保一致性
        dirs.sort((a, b) => a.name.localeCompare(b.name));

        for (const dir of dirs) {
          const subDirPath = path.join(startPath, dir.name);
          const result = await this._findExecutableFile(subDirPath);
          if (result) return result;
        }
      }
    } catch (err) {
      console.error(`读取目录失败: ${startPath}`, err);
    }

    return null;
  }

  async _searchInDirectory(dirPath, executableExt) {
    try {
      const files = await fs.promises.readdir(dirPath);

      // 过滤出具有正确扩展名的文件
      const exeFiles = files.filter((file) => {
        const ext = path.extname(file).toLowerCase();
        return ext === executableExt;
      });

      // 如果有多个匹配，优先选择与目录名相似的文件
      if (exeFiles.length > 0) {
        const dirName = path.basename(dirPath);
        const perfectMatch = exeFiles.find(
          (file) =>
            path.parse(file).name.toLowerCase() === dirName.toLowerCase()
        );

        const filePath = path.join(dirPath, perfectMatch || exeFiles[0]);
        return filePath;
      }
    } catch (err) {
      console.error(`读取目录失败: ${dirPath}`, err);
    }

    return null;
  }
  async getLocalFiles() {
    try {
      // 确保目录存在
      if (!fs.existsSync(this.localFileDir)) {
        console.warn(`目录不存在: ${this.localFileDir}`);
        return [];
      }

      // 读取目录中的文件列表
      const files = await fs.promises.readdir(this.localFileDir);

      // 过滤出 .zip 文件并获取详细信息
      const zipFiles = [];

      for (const file of files) {
        const filePath = path.join(this.localFileDir, file);
        const stats = await fs.promises.stat(filePath);

        // 判断是否为文件 并 以 .zip 结尾
        if (stats.isFile() && file.toLowerCase().endsWith(".zip")) {
          zipFiles.push({
            filename: file,
            size: stats.size, // 字节
            modifiedTime: stats.mtime, // 修改时间
          });
        }
      }

      return { success: true, message: "获取本地文件成功！", data: zipFiles };
    } catch (error) {
      console.error("读取本地文件失败:", error);
      throw new Error("无法读取本地 ZIP 文件列表");
    }
  }
  async deployLocalFiles(fileList) {
    try {
      // 确保 handleDeploy 目录存在
      if (!fs.existsSync(this.localFileDir)) {
        throw new Error(`源目录不存在: ${this.localFileDir}`);
      }
      // 确保 uploads 目录存在
      if (!fs.existsSync(this.uploadsDir)) {
        fs.mkdirSync(this.uploadsDir, { recursive: true });
      }

      const results = [];
      const deploymentPromises = [];

      for (const filename of fileList) {
        const sourceFilePath = path.join(this.localFileDir, filename);

        // 检查文件是否存在且为 .zip 文件
        if (
          fs.existsSync(sourceFilePath) &&
          filename.toLowerCase().endsWith(".zip")
        ) {
          const stats = await fs.promises.stat(sourceFilePath);
          const fileHash = path.parse(filename).name;

          // 创建初始数据库记录
          const newUpload = new Upload({
            originalName: filename,
            fileHash: fileHash,
            path: `/uploads/${filename}`,
            size: stats.size,
            mimeType: "application/x-zip-compressed",
            status: "pending",
            createdAt: new Date(),
          });

          await newUpload.save();

          // 发送开始部署通知
          socketClientManager.sendToModule("ueProject", {
            type: "deploy_started",
            payload: {
              uploadId: newUpload._id,
              fileName: filename,
              fileHash,
            },
          });

          // 异步处理部署过程
          const deploymentPromise = this._processDeployment(
            sourceFilePath,
            filename,
            fileHash,
            newUpload
          ).catch(async (error) => {
            console.error(`Deployment failed for ${filename}:`, error);
            try {
              newUpload.status = "failed";
              await newUpload.save();
              socketClientManager.sendToModule("ueProject", {
                type: "deploy_error",
                payload: {
                  uploadId: newUpload._id,
                  fileName: filename,
                  fileHash,
                  error: error.message,
                },
              });
            } catch (dbError) {
              console.error(
                `Failed to update upload status to 'failed' for ${filename} after deployment error:`,
                dbError
              );
            }
          });

          deploymentPromises.push(deploymentPromise);

          results.push({
            filename,
            status: "deploying",
            message: "文件入库已启动",
            uploadId: newUpload._id,
          });
        } else {
          results.push({
            filename,
            status: "error",
            message: "文件不存在或不是 ZIP 文件",
          });
        }
      }

      // 启动所有部署任务
      Promise.all(deploymentPromises).catch((error) => {
        console.error("Some deployments failed:", error);
      });

      return {
        success: true,
        message: "入库任务已启动，请通过WebSocket监听入库进度",
        results,
      };
    } catch (error) {
      console.error("入库本地文件失败:", error);
      throw new Error("无法完成本地文件入库");
    }
  }

  // 处理部署过程
  async _processDeployment(sourceFilePath, filename, fileHash, upload) {
    try {
      const destFilePath = path.join(this.uploadsDir, filename);

      // 复制文件
      await fs.promises.copyFile(sourceFilePath, destFilePath);

      // 删除源文件
      await fs.promises.unlink(sourceFilePath);

      // 更新部署完成状态
      upload.status = "completed";
      upload.completedAt = new Date();
      upload.extractStatus = "pending";
      await upload.save();

      // 发送部署完成通知
      socketClientManager.sendToModule("ueProject", {
        type: "deploy_completed",
        payload: {
          uploadId: upload._id,
          fileName: filename,
          fileHash,
        },
      });
    } catch (error) {
      throw error;
    }
  }
  async deleteLocalFile(fileList) {
    try {
      // 确保 handleDeploy 目录存在
      if (!fs.existsSync(this.localFileDir)) {
        throw new Error(`源目录不存在: ${this.localFileDir}`);
      }

      const results = [];
      const deletePromises = [];

      for (const filename of fileList) {
        const sourceFilePath = path.join(this.localFileDir, filename);

        // 检查文件是否存在
        if (fs.existsSync(sourceFilePath)) {
          // 发送开始删除通知
          socketClientManager.sendToModule("ueProject", {
            type: "local_file_delete_started",
            payload: {
              fileName: filename,
            },
          });

          // 异步处理删除过程
          const deletePromise = this._processLocalFileDeletion(
            sourceFilePath,
            filename
          ).catch((error) => {
            console.error(`Local file deletion failed for ${filename}:`, error);
            socketClientManager.sendToModule("ueProject", {
              type: "local_file_delete_error",
              payload: {
                fileName: filename,
                error: error.message,
              },
            });
          });

          deletePromises.push(deletePromise);

          results.push({
            filename,
            status: "deleting",
            message: "文件删除已启动",
          });
        } else {
          results.push({
            filename,
            status: "error",
            message: "文件不存在",
          });
        }
      }

      // 启动所有删除任务
      Promise.all(deletePromises).catch((error) => {
        console.error("Some local file deletions failed:", error);
      });

      return {
        success: true,
        message: "删除任务已启动，请通过WebSocket监听删除进度",
        results,
      };
    } catch (error) {
      console.error("删除本地文件失败:", error);
      throw new Error("无法完成本地文件删除");
    }
  }

  // 处理本地文件删除过程
  async _processLocalFileDeletion(sourceFilePath, filename) {
    try {
      // 删除文件
      await fs.promises.unlink(sourceFilePath);

      // 发送删除完成通知
      socketClientManager.sendToModule("ueProject", {
        type: "local_file_delete_completed",
        payload: {
          fileName: filename,
        },
      });
    } catch (error) {
      throw error;
    }
  }
}

const ueProjectManager = new UEProjectManager();
module.exports = ueProjectManager;
